package java_thinking.unit_21._21_5;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * @Desc:   5-12 使用 FutureTask 来提前加载稍后需要的数据
 *
 *          1.Callable 表示的任务可以抛出受检查的或未受检查的异常，并且任何代码都可能抛出一个 Error，
 *            无论任务代码抛出什么异常，都会被封装到一个 ExecutionException 中，并在 Future.get
 *            中被重新抛出。
 *
 *          2.get 方法抛出 ExecutionException 时，可能是一下三种情况之一：Callable 抛出的受检查异常
 *            ，RuntimeException,以及 Error;必须对每种情况但电弧处理
 * @author: cww
 * @DateTime: 2019/6/6 8:31
 */

public class Preloader {
    ProductInfo loadProductInfo() throws DataLoadException, InterruptedException {
        System.out.println("loadProductInfo");
        Thread.sleep(10000);
        return null;
    }

    /**
     * 加载所需的数据，通过 start 可以在指定时间执行加载任务；
     */
    private final FutureTask<ProductInfo> future = new FutureTask<ProductInfo>(new Callable<ProductInfo>() {
        @Override
        public ProductInfo call() throws Exception {
            return loadProductInfo();
        }
    });

    private final Thread thread = new Thread(future);

    public void start() {
        thread.start();
    }

    /**
     * 调用 get 方法，如果数据已经加载，那么将返回这些数据，否则将等待加载完成后返回；
     * @return
     * @throws DataLoadException
     * @throws InterruptedException
     */
    public ProductInfo get() throws DataLoadException, InterruptedException {
        try {
            return future.get();
        } catch (ExecutionException e) {
            Throwable cause = e.getCause();
            if (cause instanceof DataLoadException){
                throw (DataLoadException)cause;
            } else {
                throw LaunderThrowable.launderThrowable(cause);
            }
        }
    }
}


interface ProductInfo {
}

class DataLoadException extends Exception { }

class TestPreloader {
    public static void main(String[] args) throws InterruptedException {
        Preloader preloader = new Preloader();
        preloader.start();
        try {
            preloader.get();
            preloader.get();
            System.out.println("got it");
        } catch (DataLoadException e) {
            System.out.println("get DataLoadException");
        } catch (InterruptedException e) {
            System.out.println("get InterruptedException");
        }
//        Thread.sleep(12000);
        System.out.println("End");
    }
}